/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
package SteamEngineFX.Controls.Calendar.schudt;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Hyperlink;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.Popup;
import SteamEngineFX.SteamEngineFX;

/**
 *
 * @author jbendixsen
 */
public class DateHyperlink  extends HBox {


    private static final String CSS_DATE_PICKER_VALID = "datepicker-valid";
    private static final String CSS_DATE_PICKER_INVALID = "datepicker-invalid";

    private static final Image Calendar24 = new Image(SteamEngineFX.class.getResourceAsStream("/steamenginefx/resources/calendar_24.png"));
    

    /**
     * Initializes the date picker with the default locale.
     */
    public DateHyperlink() {
        this(Locale.getDefault());
    }

    private Timer timer;

    /**
     * Initializes the date picker with the given locale.
     *
     * @param locale The locale.
     */
    public DateHyperlink(Locale locale) {
        calendarView = new CalendarView(locale);

        ImageView ivCalendar = new ImageView(Calendar24);
        dateHyperlink = new Hyperlink("Selected Date");
        //dateHyperlink.locale.set(locale);
        dateHyperlink.setGraphic(ivCalendar);
        dateHyperlink.setContentDisplay(ContentDisplay.LEFT);
        dateHyperlink.getStyleClass().add("hyperlink-text");
        
        calendarView.setEffect(new DropShadow());

        // Use the same locale.
        //causing application crashing
        //calendarView.localeProperty().bind(localeProperty());

        // Bind the current date of the calendar view with the selected date, so that the calendar shows up with the same month as in the text field.
        calendarView.currentDateProperty().bind(selectedDateProperty());

        // When the user selects a date in the calendar view, hide it.
        calendarView.selectedDateProperty().addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                selectedDate.set(calendarView.selectedDateProperty().get());
                hidePopup();
            }
        });

//        // Let the prompt text property listen to locale or date format changes.
//        textField.promptTextProperty().bind(new StringBinding() {
//            {
//                super.bind(localeProperty(), promptTextProperty(), dateFormatProperty());
//            }
//
//            @Override
//            protected String computeValue() {
//                // First check, if there is a custom prompt text.
//                if (promptTextProperty().get() != null) {
//                    return promptTextProperty().get();
//                }
//
//                // If not, use the the date format's pattern.
//                DateFormat dateFormat = getActualDateFormat();
//                if (dateFormat instanceof SimpleDateFormat) {
//                    return ((SimpleDateFormat) dateFormat).toPattern();
//                }
//
//                return "";
//            }
//        });


        // Change the CSS styles, when this control becomes invalid.
        invalid.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                if (invalid.get()) {
                    dateHyperlink.getStyleClass().add(CSS_DATE_PICKER_INVALID);
                    dateHyperlink.getStyleClass().remove(CSS_DATE_PICKER_VALID);
                } else {
                    dateHyperlink.getStyleClass().remove(CSS_DATE_PICKER_INVALID);
                    dateHyperlink.getStyleClass().add(CSS_DATE_PICKER_VALID);
                }
            }
        });

        dateHyperlink.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {

                showPopup();

            }
        });

        selectedDateProperty().addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                updateHyperlink();
                invalid.set(false);
            }
        });

//        localeProperty().addListener(new InvalidationListener() {
//            @Override
//            public void invalidated(Observable observable) {
//                updateHyperlink();
//            }
//        });

        
        getChildren().add(dateHyperlink);
    }

    private void hidePopup() {
        if (popup != null) {
            popup.hide();
        }
    }

    private boolean textSetProgrammatically;

    /**
     * Updates the hyperlink text.
     */
    private void updateHyperlink() {
        // Mark the we update the text field (and not the user), so that it can be ignored, by textField.textProperty()
        textSetProgrammatically = true;
        if (selectedDateProperty().get() != null) {
            String date = getActualDateFormat().format(selectedDateProperty().get());
            if (!dateHyperlink.getText().equals(date)) {
                dateHyperlink.setText(date);
            }
        } else {
            dateHyperlink.setText("");
        }
        textSetProgrammatically = false;
    }

    /**
     * Gets the actual date format. If {@link #dateFormatProperty()} is set, take it, otherwise get a default format for the current locale.
     *
     * @return The date format.
     */
    private DateFormat getActualDateFormat() {
        if (dateFormat.get() != null) {
            return dateFormat.get();
        }

        DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT, locale.get());
        format.setCalendar(calendarView.getCalendar());
        format.setLenient(false);

        return format;
    }

    private CalendarView calendarView;

    /**
     * Use this to set further properties of the calendar.
     *
     * @return The calendar view.
     */
    public CalendarView getCalendarView() {
        return calendarView;
    }

//1    private TextField textField;
    private Hyperlink dateHyperlink;


    private BooleanProperty invalid = new SimpleBooleanProperty();

    /**
     * States whether the user input is invalid (is no valid date).
     *
     * @return The property.
     */
    public ReadOnlyBooleanProperty invalidProperty() {
        return invalid;
    }


    /**
     * The locale.
     *
     * @return The property.
     */
    public ObjectProperty<Locale> localeProperty() {
        return locale;
    }

    private ObjectProperty<Locale> locale = new SimpleObjectProperty<Locale>();

    public void setLocale(Locale locale) {
        this.locale.set(locale);
    }

    public Locale getLocale() {
        return locale.get();
    }


    /**
     * The selected date.
     *
     * @return The property.
     */
    public ObjectProperty<Date> selectedDateProperty() {
        return selectedDate;
    }

    private ObjectProperty<Date> selectedDate = new SimpleObjectProperty<Date>();

    public void setSelectedDate(Date date) {
        this.selectedDate.set(date);
    }

    public Date getSelectedDate() {
        return selectedDate.get();
    }

    /**
     * Gets the date format.
     *
     * @return The date format.
     */
    public ObjectProperty<DateFormat> dateFormatProperty() {
        return dateFormat;
    }

    private ObjectProperty<DateFormat> dateFormat = new SimpleObjectProperty<DateFormat>();

    public void setDateFormat(DateFormat dateFormat) {
        this.dateFormat.set(dateFormat);
    }

    public DateFormat getDateFormat() {
        return dateFormat.get();
    }

    private StringProperty promptText = new SimpleStringProperty();

    /**
     * The prompt text for the text field.
     * By default, the prompt text is taken from the date format pattern.
     *
     * @return The property.
     */
    public StringProperty promptTextProperty() {
        return promptText;
    }


    public void setPromptText(String promptText) {
        this.promptText.set(promptText);
    }

    public String getPromptText() {
        return promptText.get();
    }

    private Popup popup;

    /**
     * Shows the pop up.
     */
    private void showPopup() {

        if (popup == null) {
            popup = new Popup();
            popup.setAutoHide(true);
            popup.setHideOnEscape(true);
            popup.setAutoFix(true);
            popup.getContent().add(calendarView);
        }

        Bounds calendarBounds = calendarView.getBoundsInLocal();
        Bounds bounds = localToScene(getBoundsInLocal());

        double posX = calendarBounds.getMinX() + bounds.getMinX() + getScene().getX() + getScene().getWindow().getX();
        double posY = calendarBounds.getMinY() + bounds.getHeight() + bounds.getMinY() + getScene().getY() + getScene().getWindow().getY();

        popup.show(this, posX, posY);

    }
}
